package client;

import game.Game;
import game.GameObject;
import game.MagicObject;
import game.Player;

import java.awt.Point;
import java.util.HashMap;
import java.util.Map;
import java.util.Observable;

import communication.game.*;

/**
 * Variables internes du client (partie modele du MVC)
 * @author Julien Roch, Jonathan Gander, Laurent Constantin
 * @version 0.1
 */
public class ClientInternals  extends Observable{
	// Pour communiquer avec le serveur
	private NetClient netClient;
	
	// Pour lister les parties
	private Game[] gameList;
	
	// Pour lister les joueurs
	private Player[] players;
	
	/**
	 * Prochain joueur a jouer
	 * Si qqun trouve une autre solution qu'il la donne !
	 */
	private Player nextPlayer;
	
	private MagicObject objectToPlay = null;
	
	// Nom de l'utilsateur authentifie
	String userName;
	
	/**
	 * Constructeur du modele du client.
	 * @param netClient Objet network du client
	 */
	public ClientInternals(NetClient netClient){
		this.netClient = netClient;
	}
	
	/**
	 * Permet de fixer la liste de joueurs
	 * @param players Tableau de pseudo des joueurs
	 */
	public void setPlayerList(Player[] players){	
		this.players = players.clone();
		this.setChanged();
		this.notifyObservers(this.players);		
	}
	
	/**
	 * Permet de retourner la liste des joueurs
	 * @return Liste des joueurs
	 */
	public Player[] getPlayerList() {
		return players;
	}
	/**
	 * Liste des objets magiques
	 */
	private Map<Class, Integer> magicObjects;
	
	/**
	 * Permet de fixer la liste des parties
	 * @param gameList
	 */
	public void setGameList(Game[] gameList) {
		this.gameList = gameList.clone();
		
		this.setChanged();
		this.notifyObservers(this.gameList);	
	}
	
	/**
	 * Permet de retourner la liste des parties
	 * @return Liste des parties
	 */
    public Game[] getGameList(){
        return gameList;
    }
    
    /**
     * Permet de creer une nouvelle partie
     * @param name Nom de la partie
     * @param mines Nombre de mines
     * @param magicObjects Nombre d'objets magiques
     * @param dimension Dimension
     * @param playersMax Nombre de joueurs max
     * @param timePerPlayer Duree du tour pas tour
     */
    public void createGame(String name, int mines, int magicObjects, 
    		int dimension, int playersMax, int timePerPlayer) {

    	netClient.sendData(new CreateGame(name, mines, magicObjects, 
    			dimension, playersMax, timePerPlayer));
    }
    /**
     * Permet de stopper la partie en cours sur le serveur
     */
    public boolean stopGame(){
    	int id = getMyGameId();
    	if(id >= 0)
    		netClient.sendData(new StopGame(id));
    	return id >=0;
    }
    
    /**
     * Permet de demarrer une partie
     * @param game Le jeu a demarrer
     */
    public void startGame(Game game){
		netClient.sendData(new StartGame(game));
    }
    /**
     * Renvoie le numero de la partie que le client a cree.
     * Renvoie -1 sinon
     * @return Id de partie cree ou -1
     */
    private int getMyGameId(){
    	for(Game g : gameList){
    		if(g.getCreator().equals(userName))
    			return g.getId();
    		
    	}
    	return -1;
    }


    /**
     * Confirmation que la partie est debutee
     * @param gameCreated Objet pour notifier les clients
     */
    public void confirmGameCreated(ConfirmGameCreated gameCreated) {
    	this.magicObjects = new HashMap<Class, Integer>();
		this.setChanged();
		this.notifyObservers(gameCreated);
    }
    /**
     * Permet de rejoindre une partie
     * @param game Partie a joindre
     * @param pseudo Nom du joueur qui rejoind la partie
     */
    public void joinGame(Game game, String pseudo) {
    	netClient.sendData(new JoinGame(game.getId(), pseudo));
    }
    
    /**
     * Confirmation de jointure d'une partie
     * @param gameJoined Objet pour notifier les clients
     */
    public void confirmGameJoined(ConfirmGameJoined gameJoined) {
    	this.setChanged();
		this.notifyObservers(gameJoined);
    }
    
    /**
     * Indique que la partie a commence
     * @param gameStarted Objet pour notifier les clients
     */
    public void gameStarted(GameStarted gameStarted) {
    	this.setChanged();
		this.notifyObservers(gameStarted);
    }
    
    /**
     * Indique que la partie s'est terminee
     * @param gameStopped Objet pour notifier les clients
     */
    public void gameStopped(ConfirmGameFinished gameStopped) {
    	this.setChanged();
		this.notifyObservers(gameStopped);
    }
    
    /**
     * Confirmation que la partie est finie
     * @param gameFinished Objet pour notifier les clients
     */
    public void confirmGameFinished(ConfirmGameFinished gameFinished) {
    	this.setChanged();
    	this.notifyObservers(gameFinished);
    }
    
    /**
     * Joue une cellule
     * @param game La partie 
     * @param p Le point joue (coordonees)
     */
    public void playCell(Game game, Point p, MagicObject magicObject){
    	netClient.sendData(new PlayCell(game.getId(), p, magicObject));
    }
 
    /**
     * Notifie que des cellules ont etes jouees
     * @param cellsPlayed Objet pour notifier les clients
     */
    public void setPlayedCells(CellsPlayed cellsPlayed){
    	this.setChanged();
    	this.notifyObservers(cellsPlayed);
    }
    
    /**
     * Notifie pour le prochain joueur
     * @param np NextPlayer
     */
    public void setNextPlayer(NextPlayer np) {
    	this.nextPlayer = np.getPlayer();
    	this.setChanged();
    	this.notifyObservers(np);
    }
    
    /**
     * Retourne le prochain joueur
     * @return le prochain joueur
     */
    public Player getNextPlayer() {
    	return nextPlayer;
    }
    
    /**
     * Permet de quitter une partie
     * @param game Le jeu a quitter
     * @param player Le pseudo du player qui veut quitter
     */
    public void leaveGame(Game game, String player) {
    	netClient.sendData(new LeaveGame(game, player));
    }
    
    /**
     * Permet de redemarrer une partie
     * @param game Le jeu a redemarrer
     */
    public void restartGame(Game game){
		netClient.sendData(new RestartGame(game));
    }
    
    /**
     * Permet de fermer une partie (par le createur)
     * @param game Le jeu a fermer
     */
    public void closeGame(Game game) {
    	netClient.sendData(new CloseGame(game));
    }
    
    /**
     * Permet d'indiquer que le jeu est ferme par l'utilisateur
     * @param gc Objet GameClosed
     */
    public void gameClosed(GameClosed gc) {
    	this.setChanged();
    	this.notifyObservers(gc);
    }

	/**
	 * @return the objectToPlay
	 */
	public MagicObject getObjectToPlay() {
		return objectToPlay;
	}

	/**
	 * @param objectToPlay the objectToPlay to set
	 */
	public void setObjectToPlay(MagicObject objectToPlay) {
		this.objectToPlay = objectToPlay;
	}
    
	public MagicObject getObject(MagicObject o){
		Integer i = magicObjects.get(o.getClass());
		if(i!=null && i>0){
			i = i-1;
			magicObjects.put(o.getClass(), i);
			return o;
		}else{
			return null;
		}
	}
	
	public void putObject(MagicObject o){
		if(magicObjects==null)
			magicObjects = new HashMap<Class, Integer>();
		Integer i = magicObjects.get(o.getClass());
		if(i!=null){
			i = i+1;
			magicObjects.put(o.getClass(), i);
		}else{
			magicObjects.put(o.getClass(), 1);
		}
	}

	/**
	 * @return the magicObjects
	 */
	public Map<Class, Integer> getMagicObjects() {
		return magicObjects;
	}

	/**
	 * @param magicObjects the magicObjects to set
	 */
	public void setMagicObjects(Map<Class, Integer> magicObjects) {
		this.magicObjects = magicObjects;
	}

	/**
	 * @return the userName
	 */
	public String getUserName() {
		return userName;
	}
	
    
}
